/**
 * Copyright 2007-2008. Chongqing First Information & Network Co., Ltd. All
 * rights reserved. <a>http://www.cqfirst.com.cn</a>
 */
package com.cqcis.uip.base.framework.handlers.common;

import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoFuture;
import org.apache.mina.common.IoFutureListener;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.WriteFuture;
import org.apache.mina.common.support.BaseIoSession;

import com.cqcis.uip.base.framework.FrameworkConstants;
import com.cqcis.uip.base.framework.UIPServiceException;
import com.cqcis.uip.base.framework.UIPTaskException;
import com.cqcis.uip.base.framework.common.ControlMsg;
import com.cqcis.uip.base.framework.common.InterfaceLog;
import com.cqcis.uip.base.framework.common.Task;
import com.cqcis.uip.base.framework.handlers.ServerService;
import com.cqcis.uip.base.framework.utils.SessionUtil;
import com.cqcis.uip.base.framework.utils.StringUtil;
import com.cqcis.uip.base.framework.utils.TimeUtil;

/**
 * @author huangmy
 * @date   2007-12-17
 */
public abstract class AbstractServerHandler extends AbstractSocketHandler implements ServerService {
	private static Log log = LogFactory.getLog(AbstractServerHandler.class);
	private int clientNumberMax;    // 并发的最大客户端数
	private boolean keepAlive;      // 是否长连接
	
	@Override
	protected void idleSessionTo(IoSession session) {
		// do nothing
	}
	/**
	 * 生成接口日志对象且设置接收路径
	 * 
	 * @param session
	 * @param task
	 * @return
	 */
	private InterfaceLog createIntfLogAndSetRecvRecord(IoSession session, Task task) {
		if (session.getAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD_CLOSED) != null) {
			return null;// 关闭字节流记录功能
		}
		
		String file = (String)session.removeAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD);
		if (task.getAttribute(FrameworkConstants.LOG_RECORDID) == null) {
			task.setAttribute(FrameworkConstants.LOG_RECORDID, task.getTaskId());
		}
		
		String recordId = (String)task.getAttribute(FrameworkConstants.LOG_RECORDID);
		recordId = recordId == null ? task.getTaskId() : recordId;
		
		InterfaceLog intflog = new InterfaceLog(recordId, getInterfaceId());				
		intflog.setRecvTime(TimeUtil.getCurrentTime());
		intflog.setRecvRecord(getRecordPathFrom(file));
		
	    session.setAttribute(FrameworkConstants.INTERFACE_LOG, intflog);
	    
	    return intflog;
	}
	
	/**
	 * 获取接口日志对象且设置发送路径
	 * 
	 * @param session
	 * @return
	 */
	private InterfaceLog getIntfLogAndSetSendRecord(IoSession session) {
		if (session.getAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD_CLOSED) != null) {
			return null;// 关闭字节流记录功能
		}
		
		String file = (String)session.getAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD);			
		InterfaceLog intflog = (InterfaceLog)session.removeAttribute(FrameworkConstants.INTERFACE_LOG);			
		if (intflog != null && file != null) {
			intflog.setSendTime(TimeUtil.getCurrentTime());
			intflog.setSendRecord(getRecordPathFrom(file));
		}
		
		return intflog;
	}
	
	@Override
	protected void doMessageReceived(IoSession session, Object message)
			throws Exception {
		Task task = getBeforeTask(message);
		if (task == null || (task.getAttribute(FrameworkConstants.LOG_RECORDID) == null && task.getTaskId() == null)) {
			if (session.getAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD_CLOSED) == null) {
				throw new UIPServiceException("Task or Task interfaceSeq must not be null.");
			}		
		}
		
		try {
			createIntfLogAndSetRecvRecord(session, task);
		} catch (Exception e) {
			log.error("Set tin_log Exception:", e);
		}
		
		try {			
		    doReceived(session, message);
		} catch (Exception e) {
			throw new UIPServiceException("doReceived Exception: ", e);	
		}		
	}
	
	@Override
	protected void doSessionCreated(final IoSession session) throws Exception {
        Set<IoSession> sessions = session.getService().getManagedSessions(session.getServiceAddress());		
		if (clientNumberMax > 0 && sessions != null && clientNumberMax < sessions.size()) {
			WriteFuture future = session.write("Server Overloading, Close!");
			future.addListener(new IoFutureListener() {
				public void operationComplete(IoFuture f) {
					session.close();
				}
			});
			
			return;
		}
		
		if (!isStreamRecord()) {// 关闭字节流功能
			session.setAttribute(FrameworkConstants.INTERFACE_STREAM_RECORD_CLOSED, "true");
		}
		
		/*未接收到数据设置为超时*/
		setReadIdleForSession(session);
	}
	
	/**
	 * 为指定连接设置读空闲时间
	 * 
	 * @param session
	 */
	private void setReadIdleForSession(IoSession session) {
		if (getTimeout() > 0) {
			((BaseIoSession)session).increaseIdleCount(IdleStatus.READER_IDLE);
			session.setIdleTime(IdleStatus.READER_IDLE, (int)(getTimeout()/1000));
		}
	}
	
	@Override
	protected void doExceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		try {						
			InterfaceLog intflog = getIntfLogAndSetSendRecord(session);	
			if (intflog != null) {
				String sendRecord = intflog.getSendRecord();
				if (!StringUtil.hasText(sendRecord)) {
					String preMsg = (cause instanceof UIPTaskException) ? "" : (FrameworkConstants.TASK_STATE_MSG_INTERFACE_PROCESS_ERROR + ":");
					intflog.setSendRecord(preMsg + cause.getMessage());
				}
				getInterfaceLogService().insert(intflog);			    
			}			
		} catch (Exception e) {
			log.error("Save tin_log Exception:", e);
		}
	}
	
	@Override
	protected void doSessionClosed(IoSession session) throws Exception {		
		try {						
			String message = SessionUtil.isClosedByService(session) 
	        ? FrameworkConstants.TASK_STATE_MSG_SERVICE_FORCE_CLOSED_SESSION
			: FrameworkConstants.TASK_STATE_MSG_REMOTE_CLOSS_SESSION;
			
			InterfaceLog intflog = getIntfLogAndSetSendRecord(session);	
			if (intflog != null) {
				String sendRecord = intflog.getSendRecord();
				if (!StringUtil.hasText(sendRecord)) {
					intflog.setSendRecord(message);
				}
				getInterfaceLogService().insert(intflog);
			}			
		} catch (Exception e) {
			log.error("Save tin_log Exception:", e);
		}
	}
	
	@Override
	protected void doSessionIdle(final IoSession session, IdleStatus status)
			throws Exception {		
		if (status == IdleStatus.READER_IDLE) {
			WriteFuture future = session.write(new ControlMsg("Read Idle Timeout!"));
			future.addListener(new IoFutureListener() {
				public void operationComplete(IoFuture f) {
					session.close();
				}
			});		    
		}
	}
	
	@Override
	protected void doMessageSent(IoSession session, Object message)
			throws Exception {
		try {					
			InterfaceLog intflog = getIntfLogAndSetSendRecord(session);			
			if (intflog != null) {				
				getInterfaceLogService().insert(intflog);
			}
		} catch (Exception e) {
			log.error("Save tin_log Exception:", e);
		}
		
		getAfterTask(message);
		
		// 不是长连接, 服务端发完数据后关闭session
		if (!keepAlive) {
			session.close();
		} else { // 否则设置读数据空闲
			setReadIdleForSession(session);
		}
	}
	
	/**
     * 处理收到的数据
     * @param session
     * @param message
     * @throws Exception
     */
	protected void doReceived(IoSession session, Object message) throws Exception {
		Object obj = doMessageReceived(message);
		if (obj == null) {
			if (isScheduleable()) {
				return;
			}
			throw new UIPServiceException("Service NullPointException: the service returning must not be null.");
		}
		
		session.write(obj);
	}
	
	/**
	 * 是否可提交
	 * 
	 * @return
	 */
	public boolean isScheduleable() {
		return false;
	}
	
	public void registerClientNumberMax(int clientNumberMax) {
		this.clientNumberMax = clientNumberMax;
	}

	public void registerKeepAlive(boolean keepAlive) {
		this.keepAlive = keepAlive;
	}
}
